package server.io.game.conn;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

import server.io.client.HandShake;
import server.io.conn.wsp.Base_WSP13;
import server.io.game.fact.hall.Hall_Base;
import server.io.game.fact.hall.Hall_Normal;
import server.io.game.fact.player.Player_Base;
import server.io.game.fact.room.Room_Base;
import server.io.game.fact.user.User_Base;
import server.io.game.fact.user.User_Normal;
import server.io.pro.bean.Pro_AllotCardHand;
import server.io.pro.bean.Pro_AllotHero;
import server.io.pro.bean.Pro_ChooseHero;
import server.io.pro.bean.Pro_JoinHall;
import server.io.pro.bean.Pro_Login;
import server.io.pro.bean.Pro_StartGame;
import server.io.pro.ctrl.Pro_Adapter_Base;
import server.io.pro.ctrl.Pro_Adapter_Recv;
import server.io.pro.ctrl.Pro_Adapter_Send;

import com.google.gson.reflect.TypeToken;

public class RecvServer_K extends RecverThread
{
	// 静态的监听read事件的selector.
	private Selector hallSelector;
	// 是否开始监听read.
	private boolean IsThreadShutDown = false;
	// 给此监听线程加入新channel时候,用于判断
	private boolean isJoiningNew = false;
	// 是否让监听器监听,如果为false则此线程将会睡眠并且被回收
	private boolean isListen = true;
	// 大厅的id,标识此大厅
	private int hallId = 0;
	// 存住select的返回值
	private int k = 0;
	// 读取信息的缓冲区
	// private ByteBuffer r_buff = ByteBuffer.allocate(1024);
	// 存放read()方法返回的int
	private int lengthOfRead = 0;
	private SocketChannel g_channel = null;

	private int idid = 1302;

	private static ByteBuffer sendbuffer = ByteBuffer.allocate(8192);

	// 定义实现编码、解码的字符集对象
	private Charset charset = Charset.forName("UTF-8");

	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// fact

	private Hall_Normal hall = null;

	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////
	// /////////////////////////////////////////

	public RecvServer_K()
	{
		// TODO Auto-generated constructor stub
		init();
		this.hall = new Hall_Normal("small");
		this.hall.init();
	}

	@Override
	public void run()
	{
		System.out.println("Recv_Module Start...!");
		// 一开始初始化大厅监听线程时,先让其睡眠
		if (hallId == 0)
		{
			try
			{
				synchronized (this)
				{
					wait();
				}
			}
			catch (InterruptedException e1)
			{
				e1.printStackTrace();
			}
		}

		// 监听器主体
		while (!IsThreadShutDown)
		{
			while (isListen)
			{
				try
				{
					System.out.println("Waiting.. IO Data.. \n");
					k = hallSelector.select();
					if (k == 0)
					{
						// 此处给此监听器加入绑定新channel
						if (isJoiningNew)
						{
							System.out.println("One New Recv Listen..1");
							bindingNewClient();
						}
						continue;
					}

					System.out.println("一次循环  被唤醒的 "
							+ hallSelector.selectedKeys().size()
							+ " 个key, selector中一共有 "
							+ hallSelector.keys().size() + " 个key");

					Iterator<SelectionKey> it = hallSelector.selectedKeys()
							.iterator();

					while (it.hasNext())
					{

						SelectionKey key = it.next();

						it.remove();

						if (key.isReadable())
						{
							handleInput(key);
						}
					}

					// 此处给此监听器加入绑定新channel,与上面的判断双重保证此监听器能绑定到新client
					if (isJoiningNew)
					{
						System.out.println("One New Recv Listen..2");
						bindingNewClient();
					}
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 处理客户端的发入. 由管理类解析，次监听类本身判断并处理
	 * 
	 * @param argKey
	 * @throws IOException
	 */
	private void handleInput(SelectionKey argKey) throws IOException
	{
		// 由key获取指定socket channel的引用
		SocketChannel _channel = (SocketChannel) argKey.channel();
		ByteBuffer r_buff = ByteBuffer.allocate(1024);
		// 重置缓冲区
		r_buff.clear();

		try
		{
			lengthOfRead = _channel.read(r_buff);

			// if语句
			if (lengthOfRead > 0)
			{
				// r_buff.flip();
				// String content = "";
				// CharBuffer c = charset.decode(r_buff);
				// content = c.toString();

				r_buff.flip();

				byte[] bytes = new byte[r_buff.remaining()];
				r_buff.get(bytes);
				
				String content = mCtrlWsp.control(bytes, _channel);

				System.out.println("Server revc:\n" + content + "\nEnd recv");
				if ("handeshake".equals(content))
				{
					//
				}
				else
				{
					// 协议适配器
					Pro_Adapter_Recv _proAdp_Recv = new Pro_Adapter_Recv();
					Pro_Adapter_Send _proAdp_Send = new Pro_Adapter_Send();
					int _proId = _proAdp_Recv.parseHead(content);
					// 要发送的数据
					String _sendData_str = null;
					byte[] _sendData_byte = null;
					Type _beanType = null;
					// // 临时
					User_Base _user = null;
					Room_Base _room = null;
					Hall_Base _hall = null;
					Player_Base _player = null;
					// 501 - 9499
					if (_proId > 1000 && _proId < 4500)
					{
						_user = (User_Base) argKey.attachment();
						_hall = (Hall_Base) _user.getInfo("hall");
						if (_hall != null)
						{
							_hall.control(_proId, content, argKey);
						}
					}
					else if (_proId > 5000 && _proId < 9500)
					{
						_user = (User_Base) argKey.attachment();
						_room = (Room_Base) _user.getInfo("room");
						if (_room != null)
						{
							_room.control(_proId, content, argKey);
						}
					}
					else
					{
						switch (_proId)
						{
						case 11:
							HandShake _handShake = new HandShake();
							_sendData_byte = _handShake.createProtocal(content);
							break;
						// 登录
						case 501:
							Pro_Login _login = new Pro_Login();
							_login._recv = Pro_Adapter_Base
									.<Pro_Login.Recv> jsonToObject(content,
											Pro_Login.Recv.class);
							// 登陆成功
							_user = new User_Normal(++idid,
									_login._recv.username);
							_user.nat_clientInfo.channel = _channel;
							argKey.attach(_user);
							// 协议是一个对象
							_login._send = _login.new Send("ok",
									_user.user_name, _user);
							// 把这个协议对象转成string
							_sendData_byte = _proAdp_Send
									.encapProtocol(_login._send);
							break;
						// 进入房间
						case 851:
							Pro_JoinHall _joinHall = new Pro_JoinHall();
							this.hall.join(argKey);
							_joinHall._send = _joinHall.new Send(this.hall);
							_sendData_byte = _proAdp_Send
									.encapProtocol(_joinHall._send);
							break;

						// 开始游戏
						case 1055:
							_beanType = new TypeToken<Pro_StartGame.Recv>()
							{
							}.getType();
							Pro_StartGame _startGame = new Pro_StartGame();
							_startGame._recv = (Pro_StartGame.Recv) _proAdp_Recv
									.parseProtocol(content, _beanType);

							// _room = (Room_Base) getAttach(argKey, "room");
							_room.startGame();

							// 协议是一个对象
							_startGame._send = _startGame.new Send(_room.game);
							// 把这个协议对象转成string
							_sendData_byte = _proAdp_Send
									.encapProtocol(_startGame._send);
							break;
						// 分配可选武将
						case 1059:

							_beanType = new TypeToken<Pro_AllotHero.Recv>()
							{
							}.getType();

							Pro_AllotHero _allotHero = new Pro_AllotHero();

							_allotHero._recv = (Pro_AllotHero.Recv) _proAdp_Recv
									.parseProtocol(content, _beanType);

							// _room = (Room_Base) this.getAttach(argKey,
							// "room");
							_player = _room.game.allotHero(argKey);

							// 协议是一个对象
							_allotHero._send = _allotHero.new Send(_player);

							// 把这个协议对象转成string
							_sendData_byte = _proAdp_Send
									.encapProtocol(_allotHero._send);
							// 再转成封装成websocket协议的byte[]
							break;
						// 选择武将
						case 1061:
							_beanType = new TypeToken<Pro_ChooseHero.Recv>()
							{
							}.getType();
							Pro_ChooseHero _chooseHero = new Pro_ChooseHero();
							_chooseHero._recv = (Pro_ChooseHero.Recv) _proAdp_Recv
									.parseProtocol(content, _beanType);
							// _room = (Room_Base) getAttach(argKey, "room");
							_room.game.chooseHero(argKey,
									_chooseHero._recv.hero_factid);
							// 协议是一个对象
							_chooseHero._send = _chooseHero.new Send(
									_room.game.players);
							// 把这个协议对象转成string
							_sendData_byte = _proAdp_Send
									.encapProtocol(_chooseHero._send);
							break;
						// 分配手牌
						case 1063:

							_beanType = new TypeToken<Pro_AllotCardHand.Recv>()
							{
							}.getType();

							Pro_AllotCardHand _allotHandCard = new Pro_AllotCardHand();

							_allotHandCard._recv = (Pro_AllotCardHand.Recv) _proAdp_Recv
									.parseProtocol(content, _beanType);

							// _room = (Room_Base) getAttach(argKey, "room");
							_player = _room.game.allotCardHand(argKey);

							// 协议是一个对象
							_allotHandCard._send = _allotHandCard.new Send(
									_player.card_hand);

							// 把这个协议对象转成string
							_sendData_byte = _proAdp_Send
									.encapProtocol(_allotHandCard._send);
							// 再转成封装成websocket协议的byte[]
							break;
						default:
							break;
						}
						System.out.println("server send:\n"
								+ new String(_sendData_byte));
						sendbuffer.clear();
						sendbuffer.put(_sendData_byte);
						sendbuffer.flip();
						_channel.write(sendbuffer);
						System.out.println("One Select End ..!");
					}
				}

			} // 若断线,cancel掉此通道
			else if (lengthOfRead == -1)
			{
				System.out.println("!!!!!!! Close One Connect!(in length=-1)");
				User_Base _user = (User_Base) argKey.attachment();
				if (_user != null)
				{
					_user.clear();
				}
				// 关闭此channel
				_channel.close();
				// 删掉此key
				argKey.cancel();
			}
		}
		catch (Exception e)
		{
			// 出错而已
			System.out.println("!!!!!!! Close One Connect!(in catch)");
			e.printStackTrace();
		}
	}

	private void init()
	{

		try
		{
			hallSelector = Selector.open();
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 进入大厅的同步性问题,保证一次一个.做一个lock,等待模式. set进channel的同时把isJoiningNew赋值为true
	 * 
	 * @param argUser
	 * @param argSign
	 */
	public void setUserInHall(SocketChannel aChannel, int argSign)
	{
		this.g_channel = aChannel;
		isJoiningNew = true;
		hallSelector.wakeup();
	}

	// 为大厅赋值自身id后，唤醒此大厅线程
	public synchronized void setHallId(int argHallId)
	{
		this.hallId = argHallId;
		this.notify();
	}

	private void bindingNewClient()
	{
		// 加入新玩家进入大厅,邦定selector
		// 新玩家加入时候触发此方法,邦定成功并且加入队列成功才继续
		if (handleNewJoining(g_channel, hallSelector))
		{
			isJoiningNew = false;
		}
		else
		{
			isJoiningNew = false;
		}
	}

	public void sleepThisListener()
	{
		isListen = false;
		try
		{
			hallSelector.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	public boolean handleNewJoining(SocketChannel argChannel, Selector argSelect)
	{
		try
		{

			argChannel.configureBlocking(false);
			argChannel.register(argSelect, SelectionKey.OP_READ, null);
			return true;
		}
		catch (IOException e)
		{
			e.printStackTrace();
			return false;
		}
	}
}